# package.py -- tools for packaging.

import os
from lxml import etree
from glob import glob
from amplitude.lib.rglob import rglob
from amplitude.files.xml import XML
from amplitude.files.text import Text
import zipfile
import tempfile

DEBUG = False
MAX_SIZE = 1e8  # maximum 100MB zip size

def zip_path(path, xslpath, csspath=None, format='.xml'):
    """zip the contents of the given path, including images. return the zip itself. formats:
    xml -- the files as they appear, include linked art, includes, and stylesheets
    html -- convert to html, include linked stylesheets and art, embed included files
    ms -- "manuscript" = doctored html: embed stylesheet, change img refs to spans, no xml_declaration (so Word can load)
    """
    if os.path.isfile(path):
        fns = [path]
    elif os.path.isdir(path):
        fns = [fn.replace("\\", "/") for fn in glob(path+"/*.xml")]
    if len(fns)==0: 
        return ''

    supportfns = []    
    cssfns = []
    inclfns = []

    # gather include_items
    for fn in fns:
        doc = XML(fn)
        for incl in doc.root.xpath("//include[@src]"):
            fp = os.path.abspath(os.path.join(os.path.dirname(fn), incl.get('src'))).replace("\\", '/')
            if os.path.isfile(fp) and fp not in fns:
                if DEBUG==True: print "FNS APPEND", fp
                inclfns.append(fp)

    if format != '.html':
        fns += inclfns
            
    if format != '.xml':
        # get stylesheets
        if csspath is not None:
            cssfns = [fn.replace("\\", '/') for fn in rglob(csspath, "*.css")]
            if format != '.ms':
                supportfns += cssfns

        # gather artfiles and imgs
        for fn in fns + inclfns:
            doc = XML(fn)
            for artfile in doc.root.xpath("//artfile[@img]"):
                fp = os.path.abspath(os.path.join(os.path.dirname(fn), artfile.get('img'))).replace("\\", '/')
                if os.path.isfile(fp) and fp not in supportfns:
                    supportfns.append(fp)
            for img in doc.root.xpath("//img[@src]"):
                fp = os.path.abspath(os.path.join(os.path.dirname(fn), img.get('src'))).replace("\\", '/')
                if os.path.isfile(fp) and fp not in supportfns:
                    supportfns.append(fp)

    basepath = os.path.commonprefix(fns+supportfns)
    if basepath == fns[0] or not os.path.isdir(basepath): 
        basepath = os.path.dirname(fns[0])
    if DEBUG==True: print "basepath =", basepath
    
    f, zfn = tempfile.mkstemp()
    os.close(f)
    zf = zipfile.ZipFile(zfn, 'w', zipfile.ZIP_DEFLATED)
    if DEBUG==True: print "zipfile =", zfn
    
    htmlns = {'h': "http://www.w3.org/1999/xhtml"}
    
    if DEBUG==True: print len(fns), "fns"
    zipsize = 0

    for fn in fns:
        if zipsize > MAX_SIZE: break
        if DEBUG==True: print fn
        doc = XML(fn)
        # include filenames in zip package
        if format=='.html':
            doc.root = doc.html(xslpath=xslpath)
            doc.fn = os.path.splitext(fn)[0]+'.html'
            # link to stylesheets
            head = doc.root.xpath('h:head', namespaces=htmlns)[0]
            for cssfn in cssfns:
                link = etree.SubElement(head, 'link')
                link.set('rel', 'stylesheet')
                link.set('type', 'text/css')
                link.set('href', os.path.relpath(cssfn, os.path.dirname(fn)).replace("\\", '/'))
        elif format=='.ms':
            doc.root = doc.html(xslpath=xslpath, xslfn=os.path.join(xslpath, 'items_to_ms.xsl'))
            doc.fn = os.path.splitext(fn)[0]+'.html'
            # embed stylesheets
            head = doc.root.xpath('h:head', namespaces=htmlns)[0]
            for cssfn in cssfns:
                css = Text(cssfn)
                style = etree.SubElement(head, 'style')
                style.set('type', 'text/css')
                style.text = css.text

        tf, tfn = tempfile.mkstemp()
        if format=='.ms': 
            doc.write(fn=tfn, xml_declaration=False)
        else:
            doc.write(fn=tfn)
        zp = os.path.relpath(doc.fn, basepath).replace("\\", '/')
        zf.write(tfn, zp)
        zipsize += zf.getinfo(zp).compress_size
        os.close(tf)
        os.remove(tfn)

    for fn in supportfns:
        if zipsize > MAX_SIZE: break        
        if DEBUG==True: print fn
        rp = os.path.relpath(fn, basepath).replace("\\", '/')
        zf.write(fn, rp)
        zipsize += zf.getinfo(zp).compress_size
        
    zf.close()
    f = open(zfn, 'rb')
    zt = f.read()
    f.close()
    os.remove(zfn)
    
    return zt